package org.apache.servicecomb.samples.practise.houserush.sale.service;

import com.alibaba.fastjson.JSON;
import org.apache.http.HttpStatus;
import org.apache.servicecomb.provider.pojo.RpcReference;
import org.apache.servicecomb.samples.practise.houserush.sale.dao.FavoriteDao;
import org.apache.servicecomb.samples.practise.houserush.sale.dao.HouseOrderDao;
import org.apache.servicecomb.samples.practise.houserush.sale.dao.SaleDao;
import org.apache.servicecomb.samples.practise.houserush.sale.dao.SaleQualificationDao;
import org.apache.servicecomb.samples.practise.houserush.sale.entity.Favorite;
import org.apache.servicecomb.samples.practise.houserush.sale.entity.HouseOrder;
import org.apache.servicecomb.samples.practise.houserush.sale.entity.Sale;
import org.apache.servicecomb.samples.practise.houserush.sale.entity.SaleQualification;
import org.apache.servicecomb.samples.practise.houserush.sale.redis.RedisKey;
import org.apache.servicecomb.samples.practise.houserush.sale.redis.RedisUtil;
import org.apache.servicecomb.samples.practise.houserush.sale.rpc.RealestateApi;
import org.apache.servicecomb.samples.practise.houserush.sale.rpc.po.Realestate;
import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
import org.apache.servicecomb.tracing.Span;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class HouseOrderServiceImpl implements HouseOrderService {
    @RpcReference(microserviceName = "realestate", schemaId = "realestateApiTest")
    private RealestateApi realestateApi;
    @Autowired
    private HouseOrderDao houseOrderDao;

    @Autowired
    private SaleDao saleDao;

    @Autowired
    private FavoriteDao favoriteDao;

    @Override
    public List<Sale> indexSales() {

        return saleDao.findAll();
    }

    @Override
    public Sale findSale(int saleId) {
        Sale sale = saleDao.findOne(saleId);

        Realestate realestate = realestateApi.findRealestate(sale.getRealestateId());

        sale.setRealestateNme(realestate.getName());

        return sale;
    }

    @Override
    public List<Sale> findSaleByRealestateId(int realestateId) {
        return saleDao.findByRealestateId(realestateId);
    }

    @Override
    public Sale createSale(Sale sale) {
        List<HouseOrder> houseOrders = sale.getHouseOrders();
        sale.setHouseOrders(null);
        Sale saleResult = saleDao.save(sale);
        List<Integer> houseId = new ArrayList<>();
        houseOrders.forEach(houseOrder -> {
            Sale s = new Sale();
            s.setId(saleResult.getId());
            houseOrder.setSale(s);
            houseId.add(houseOrder.getHouseId());
        });
        List<HouseOrder> houseOrders1 =
                houseOrderDao.save(houseOrders);
        saleResult.setHouseOrders(houseOrders1);
        realestateApi.lockHousesForSale(houseId);
        return sale;

    }

    @Override
    public Sale updateSale(Sale sale) {
        int id = sale.getId();
        if (saleDao.exists(id)) {
            return saleDao.save(sale);
        } else {
            throw new DataRetrievalFailureException("无法更新不存在的活动条目");
        }
    }

    @Override
    public void removeSale(int saleId) {
        Sale sale = findSale(saleId);
        List<Integer> ids = new ArrayList<>();
//查询房源信息
        sale.getHouseOrders().forEach(houseOrder -> {
            ids.add(houseOrder.getHouseId());
        });
//删除活动，相关的房源解锁
        if (!ids.isEmpty()) {
            realestateApi.updateReleaseLockingStatesForHouses(ids);
        }
        saleDao.delete(saleId);
    }

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private RedisKey redisKey;

    @Override
    @Span
    public Sale findOrderSale(int saleId) {
        //基于redis的查询活动
        Sale sale;
        String saleKey = redisKey.getSaleKey(saleId);
        String saleHashKey = redisKey.getSaleHashKey(saleId);
        String saleStr = redisUtil.get((saleKey));
        //获取redis中的数据，判断是否为空
        if (saleStr == null) {
            sale = saleDao.findOne(saleId);
            if (sale == null) {
                return null;
            }
            List<HouseOrder> houseOrders = sale.getHouseOrders();
            for (HouseOrder houseOrder : houseOrders) {
                houseOrder.setSale(null);
            }
            redisUtil.set(redisKey.getSaleNoHouseOrder(saleId), JSON.toJSONString(sale, 500));
            sale.setHouseOrders(houseOrders);
        } else {
            sale = JSON.parseObject(saleStr, Sale.class);
        }
        Map<Object, Object> map = redisUtil.hmget(saleHashKey);
        if (map == null || map.size() == 0) {
            for (HouseOrder houseOrder : sale.getHouseOrders()) {
                //为了前台为了抢房的过程中可以快速判断能否抢购
                map.put(houseOrder.getId().toString(), houseOrder.getState());
            }
            redisUtil.hmset(saleHashKey, map, 500);
        }
        for (HouseOrder h : sale.getHouseOrders()) {
            h.setState(map.get(h.getId() + "").toString());
            h.setSale(null);
            h.setCustomerId(null);
            h.setOrderedAt(null);
            h.setCreatedAt(null);
            h.setUpdatedAt(null);
            h.setHouseId(null);
            h.setFavoriteList(null);
        }
        return sale;
    }

    @Autowired
    private SaleQualificationDao saleQualificationDao;

    @Override
    @Transactional
    public void updateSaleQualification(List<SaleQualification> saleQualifications) {
        if (null != saleQualifications) {
            for (SaleQualification saleQualification : saleQualifications) {
                SaleQualification bySaleIdAndCustomerId = saleQualificationDao.
                        findBySaleIdAndCustomerId(saleQualification.getSaleId(),
                                saleQualification.getCustomerId());
                if (null == bySaleIdAndCustomerId) {
                    //结果为空则新增，下单数为0
                    saleQualification.setOrderCount(0);
                    saleQualificationDao.save(saleQualification);
                } else {
                    bySaleIdAndCustomerId.setQualificationCount(saleQualification.
                            getQualificationCount());
                    saleQualificationDao.save(saleQualification);
                }
            }
        }
    }

    @Override
    @Transactional
    public void removeSaleQualification(int customerId) {
        saleQualificationDao.deleteAllByCustomerId(customerId);
    }

    @Override
    public int countHouseBySaleId(int saleId) {
        return houseOrderDao.countBySaleId(saleId);
    }

    @Override
    public List<Favorite> findMyFavorite(int customerId) {
        return favoriteDao.findAllByCustomerId(customerId);
    }

    @Override
    @Transactional
    public Favorite addFavorite(int customerId, int houseOrderId) {
        //根据房源订单id查询房源
        HouseOrder houseOrder = houseOrderDao.findOne(houseOrderId);
        //判断房源是否为空
        if (null == houseOrder) {
            throw new InvocationException(HttpStatus.SC_BAD_REQUEST, "", "房源订单不存在");
        }
        if (favoriteDao.countByCustomerIdAndHouseOrderId(customerId, houseOrderId) == 0) {
            //可以收藏
            Favorite favorite = new Favorite();
            favorite.setCustomerId(customerId);
            favorite.setHouseOrderId(houseOrderId);
            favoriteDao.save(favorite);
            return favorite;
        } else {
            //如果不为空在判断，根据房源id和客户id查询收藏条目数量，如果为0
            //表明该客户没有收藏过该房源订单
            throw new InvocationException(HttpStatus.SC_BAD_REQUEST, "", "房源已经被收藏");
        }
    }

    @Override
    public Favorite findFavorite(int id) {
        return favoriteDao.findOne(id);
    }

    @Override
    public void removeFavorite(int id) {
        favoriteDao.delete(id);

    }

    @Override
    public HouseOrder findOne(int houseOrderId) {
        return houseOrderDao.findOne(houseOrderId);
    }

    @Override
    public HouseOrder findAllByHouseId(Integer houseId) {
        return houseOrderDao.findAllByHouseId(houseId);
    }

    @Override
    public List<HouseOrder> findAllByCustomerId(int customerId) {
        return houseOrderDao.findAllByCustomerId(customerId);
    }

    @Override
    public List<SaleQualification> findByCustomerId(int customerId) {
        return saleQualificationDao.findByCustomerId(customerId);
    }

    @Override
    public SaleQualification findBySaleIdAndCustomerId(int saleId,int customerId) {
        SaleQualification bySaleIdAndCustomerId = saleQualificationDao.findBySaleIdAndCustomerId(saleId, customerId);
        return bySaleIdAndCustomerId;
    }

    @Override
    @Transactional
    public HouseOrder placeHouseOrder(int customerId, int houseOrderId, int saleId, int orderId) {
        //获取房源订单状态Key，从redis中拿
        String saleHashKey = redisKey.getSaleHashKey(saleId);
        //根据房源订单的状态key获取订单状态
        Object state = redisUtil.hget(saleHashKey, houseOrderId + "");

        //如果已经认购了直接抛异常
        if("confirmed".equals(state)) {
            throw new InvocationException(HttpStatus.SC_BAD_REQUEST,"","房源已经被抢购");
        }

        //未认购状态
        //判断活动是否已经开始
        if(isSaleOpen(saleId)) {
            SaleQualification bySaleIdAndCustomerId = saleQualificationDao.
                    findBySaleIdAndCustomerId(saleId, customerId);
            if(!bySaleIdAndCustomerId.hasPlaceQualification()) {
                throw new InvocationException(HttpStatus.SC_BAD_REQUEST,"","没有足够的房源，房源数是 ： " + bySaleIdAndCustomerId.getQualificationCount() + "已认购的总数是： " + bySaleIdAndCustomerId.getOrderCount());

            }
            HouseOrder houseOrder = new HouseOrder();
            houseOrder.setId(houseOrderId);
            houseOrder.setState("confirmed");
            houseOrder.setOrderedAt(new Date());
            houseOrder.setCustomerId(customerId);

            int i = houseOrderDao.updateByIdAndCustomerIdIsNull(customerId, houseOrder.getState(),
                    houseOrder.getOrderedAt(), houseOrderId);
            if(i < 1) {
                redisUtil.hset(saleHashKey,houseOrderId + "","confirmed",600);
                throw new InvocationException(HttpStatus.SC_BAD_REQUEST,"","房源已经被抢购");
            }
            bySaleIdAndCustomerId.addOrderCount();
            saleQualificationDao.saveAndFlush(bySaleIdAndCustomerId);
            redisUtil.hset(saleHashKey,houseOrderId + "","confirmed",600);
            return houseOrder;

        } else {
            throw new InvocationException(HttpStatus.SC_BAD_REQUEST,"","该房源目前无法出手");
        }

        //只有当活动已经开始了才能查询

        //活动开始，需要查询活动资格数据

        //判断活动是否可以下单

    }

    @Override
    @Transactional
    public HouseOrder cancelHouseOrder(int customerId, int houseOrderId, int orderId) {
        //根据房源订单id 查询
        HouseOrder houseOrder = houseOrderDao.findOneForUpdate(houseOrderId);
        Sale sale = houseOrder.getSale();
        if(null != sale && "opening".equals(sale.getState())) {
            if(customerId == houseOrder.getCustomerId().intValue()) {
                houseOrder.setCustomerId(null);
                houseOrder.setState("new");
                houseOrder.setOrderedAt(null);
                houseOrderDao.save(houseOrder);

                //清理redis
                redisUtil.hdel(redisKey.getSaleHashKey(houseOrder.getSale().getId()),houseOrderId+ "");
                SaleQualification saleQualification = saleQualificationDao.findBySaleIdAndCustomerId(sale.getId(), customerId);
                saleQualification.minusOrderCount();;
                saleQualificationDao.saveAndFlush(saleQualification);
                return houseOrder;
            } else {
                throw new InvocationException(HttpStatus.SC_BAD_REQUEST, "", "客户不能取消未认购的房源订单");
            }
        } else {
            throw new InvocationException(HttpStatus.SC_BAD_REQUEST, "", "活动未开始或活动为空");
        }
    }

    //判断活动是否已经开始了
    private boolean isSaleOpen(int saleId) {
        //从redis中查询活动信息
        String s = redisUtil.get(redisKey.getSaleNoHouseOrder(saleId));
        //判断结果是否为空
        //如果为空，从mysql中查询数据，并设置到redis中
        if(s == null) {
            Sale sale = saleDao.findOne(saleId);
            if(sale == null) {
                return false;
            }
            sale.setHouseOrders(null);
            s = JSON.toJSONString(s);
            redisUtil.set(redisKey.getSaleNoHouseOrder(saleId),s,600);
        //如果不为空。解析活动数据
        }
        Sale sale = JSON.parseObject(s, Sale.class);


        //返回活动是否开始的判断结果
        return "opening".equals(sale.getState());
    }



}
